<!doctype html>
<html lang="zh-CN">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>前端 ECDSA 示例</title>
		<script src="https://cdn.tailwindcss.com"></script>
		<link
			href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css"
			rel="stylesheet" />
		<script>
			tailwind.config = {
				theme: {
					extend: {
						colors: {
							primary: "#3B82F6",
							secondary: "#10B981",
							accent: "#8B5CF6",
							dark: "#1E293B",
							light: "#F8FAFC"
						},
						fontFamily: {
							inter: ["Inter", "system-ui", "sans-serif"]
						}
					}
				}
			};
		</script>
		<style type="text/tailwindcss">
			@layer utilities {
				.content-auto {
					content-visibility: auto;
				}
				.card-shadow {
					box-shadow:
						0 10px 15px -3px rgba(0, 0, 0, 0.1),
						0 4px 6px -2px rgba(0, 0, 0, 0.05);
				}
				.text-gradient {
					background-clip: text;
					-webkit-background-clip: text;
					color: transparent;
					background-image: linear-gradient(to right, #3b82f6, #8b5cf6);
				}
			}
		</style>
	</head>
	<body class="bg-gray-50 font-inter min-h-screen flex flex-col">
		<!-- 导航栏 -->
		<header
			class="bg-white shadow-md sticky top-0 z-50 transition-all duration-300"
			id="navbar">
			<div class="container mx-auto px-4 py-3 flex justify-between items-center">
				<div class="flex items-center space-x-2">
					<i class="fa fa-shield text-primary text-2xl"></i>
					<h1 class="text-xl font-bold text-dark">
						ECDSA <span class="text-primary">前端示例</span>
					</h1>
				</div>
				<nav class="hidden md:flex space-x-6">
					<a href="#generate" class="text-gray-600 hover:text-primary transition-colors"
						>生成密钥</a
					>
					<a href="#sign" class="text-gray-600 hover:text-primary transition-colors"
						>签名消息</a
					>
					<a href="#verify" class="text-gray-600 hover:text-primary transition-colors"
						>验证签名</a
					>
					<a href="#about" class="text-gray-600 hover:text-primary transition-colors"
						>关于 ECDSA</a
					>
				</nav>
				<button class="md:hidden text-gray-600 focus:outline-none" id="menu-toggle">
					<i class="fa fa-bars text-xl"></i>
				</button>
			</div>
			<!-- 移动端菜单 -->
			<div class="md:hidden hidden bg-white shadow-lg absolute w-full" id="mobile-menu">
				<div class="container mx-auto px-4 py-2 flex flex-col space-y-3">
					<a
						href="#generate"
						class="text-gray-600 hover:text-primary py-2 transition-colors"
						>生成密钥</a
					>
					<a href="#sign" class="text-gray-600 hover:text-primary py-2 transition-colors"
						>签名消息</a
					>
					<a
						href="#verify"
						class="text-gray-600 hover:text-primary py-2 transition-colors"
						>验证签名</a
					>
					<a href="#about" class="text-gray-600 hover:text-primary py-2 transition-colors"
						>关于 ECDSA</a
					>
				</div>
			</div>
		</header>

		<!-- 主内容 -->
		<main class="flex-grow container mx-auto px-4 py-8">
			<!-- 英雄区域 -->
			<section class="mb-16 text-center">
				<h2 class="text-[clamp(2rem,5vw,3.5rem)] font-bold mb-4 text-gradient">
					前端 ECDSA 数字签名
				</h2>
				<p class="text-lg text-gray-600 max-w-3xl mx-auto mb-8">
					使用椭圆曲线数字签名算法在浏览器中实现安全的消息签名和验证
				</p>
				<div class="flex flex-wrap justify-center gap-4">
					<a
						href="#generate"
						class="bg-primary hover:bg-primary/90 text-white px-6 py-3 rounded-lg transition-all duration-300 transform hover:scale-105 shadow-lg hover:shadow-xl flex items-center">
						<i class="fa fa-key mr-2"></i> 生成密钥对
					</a>
					<a
						href="#about"
						class="bg-white hover:bg-gray-50 text-primary border border-primary px-6 py-3 rounded-lg transition-all duration-300 transform hover:scale-105 shadow-md hover:shadow-lg flex items-center">
						<i class="fa fa-info-circle mr-2"></i> 了解更多
					</a>
				</div>
			</section>

			<!-- 功能区域 -->
			<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
				<!-- 生成密钥对 -->
				<section
					id="generate"
					class="bg-white rounded-xl p-6 card-shadow transform transition-all duration-300 hover:shadow-xl hover:-translate-y-1">
					<div
						class="w-12 h-12 bg-primary/10 rounded-full flex items-center justify-center mb-4">
						<i class="fa fa-key text-primary text-xl"></i>
					</div>
					<h3 class="text-xl font-bold mb-4 text-dark">生成密钥对</h3>
					<p class="text-gray-600 mb-6">点击下方按钮生成 ECDSA 密钥对（公钥和私钥）。</p>
					<button
						id="generate-keys"
						class="w-full bg-primary hover:bg-primary/90 text-white py-3 rounded-lg transition-all duration-300 flex items-center justify-center">
						<i class="fa fa-refresh mr-2"></i> 生成密钥对
					</button>
					<div class="mt-6">
						<div class="mb-4">
							<label class="block text-sm font-medium text-gray-700 mb-1"
								>公钥 (PEM 格式)</label
							>
							<div class="relative">
								<textarea
									id="public-key"
									class="w-full h-32 p-3 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary resize-none text-sm"
									readonly></textarea>
								<button
									class="absolute right-3 top-3 text-gray-400 hover:text-primary transition-colors"
									id="copy-public-key">
									<i class="fa fa-copy"></i>
								</button>
							</div>
						</div>
						<div>
							<label class="block text-sm font-medium text-gray-700 mb-1"
								>私钥 (PEM 格式)</label
							>
							<div class="relative">
								<textarea
									id="private-key"
									class="w-full h-32 p-3 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary resize-none text-sm"
									readonly></textarea>
								<button
									class="absolute right-3 top-3 text-gray-400 hover:text-primary transition-colors"
									id="copy-private-key">
									<i class="fa fa-copy"></i>
								</button>
							</div>
						</div>
					</div>
				</section>

				<!-- 签名消息 -->
				<section
					id="sign"
					class="bg-white rounded-xl p-6 card-shadow transform transition-all duration-300 hover:shadow-xl hover:-translate-y-1">
					<div
						class="w-12 h-12 bg-secondary/10 rounded-full flex items-center justify-center mb-4">
						<i class="fa fa-pencil-square-o text-secondary text-xl"></i>
					</div>
					<h3 class="text-xl font-bold mb-4 text-dark">签名消息</h3>
					<p class="text-gray-600 mb-4">使用私钥对消息进行签名，生成数字签名。</p>
					<div class="mb-4">
						<label class="block text-sm font-medium text-gray-700 mb-1">消息</label>
						<textarea
							id="message-to-sign"
							class="w-full h-20 p-3 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary resize-none text-sm"
							placeholder="请输入要签名的消息..."></textarea>
					</div>
					<div class="mb-4">
						<label class="block text-sm font-medium text-gray-700 mb-1">私钥</label>
						<div class="relative">
							<textarea
								id="private-key-sign"
								class="w-full h-20 p-3 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary resize-none text-sm"
								placeholder="请粘贴您的私钥..."></textarea>
							<button
								class="absolute right-3 top-3 text-gray-400 hover:text-primary transition-colors"
								id="use-generated-private-key">
								<i class="fa fa-arrow-right"></i>
							</button>
						</div>
					</div>
					<button
						id="sign-message"
						class="w-full bg-secondary hover:bg-secondary/90 text-white py-3 rounded-lg transition-all duration-300 flex items-center justify-center">
						<i class="fa fa-pencil mr-2"></i> 签名消息
					</button>
					<div class="mt-6">
						<label class="block text-sm font-medium text-gray-700 mb-1"
							>签名结果 (Base64)</label
						>
						<div class="relative">
							<textarea
								id="signature-result"
								class="w-full h-24 p-3 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary resize-none text-sm"
								readonly></textarea>
							<button
								class="absolute right-3 top-3 text-gray-400 hover:text-primary transition-colors"
								id="copy-signature">
								<i class="fa fa-copy"></i>
							</button>
						</div>
					</div>
				</section>

				<!-- 验证签名 -->
				<section
					id="verify"
					class="bg-white rounded-xl p-6 card-shadow transform transition-all duration-300 hover:shadow-xl hover:-translate-y-1">
					<div
						class="w-12 h-12 bg-accent/10 rounded-full flex items-center justify-center mb-4">
						<i class="fa fa-check-circle-o text-accent text-xl"></i>
					</div>
					<h3 class="text-xl font-bold mb-4 text-dark">验证签名</h3>
					<p class="text-gray-600 mb-4">使用公钥验证消息和签名是否匹配。</p>
					<div class="mb-4">
						<label class="block text-sm font-medium text-gray-700 mb-1">原始消息</label>
						<textarea
							id="message-to-verify"
							class="w-full h-16 p-3 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary resize-none text-sm"
							placeholder="请输入原始消息..."></textarea>
					</div>
					<div class="mb-4">
						<label class="block text-sm font-medium text-gray-700 mb-1">公钥</label>
						<div class="relative">
							<textarea
								id="public-key-verify"
								class="w-full h-16 p-3 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary resize-none text-sm"
								placeholder="请粘贴公钥..."></textarea>
							<button
								class="absolute right-3 top-3 text-gray-400 hover:text-primary transition-colors"
								id="use-generated-public-key">
								<i class="fa fa-arrow-right"></i>
							</button>
						</div>
					</div>
					<div class="mb-4">
						<label class="block text-sm font-medium text-gray-700 mb-1"
							>签名 (Base64)</label
						>
						<textarea
							id="signature-to-verify"
							class="w-full h-16 p-3 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary resize-none text-sm"
							placeholder="请粘贴签名..."></textarea>
					</div>
					<button
						id="verify-signature"
						class="w-full bg-accent hover:bg-accent/90 text-white py-3 rounded-lg transition-all duration-300 flex items-center justify-center">
						<i class="fa fa-check mr-2"></i> 验证签名
					</button>
					<div class="mt-6 text-center">
						<div
							id="verification-result"
							class="py-3 px-4 rounded-lg font-medium"></div>
					</div>
				</section>
			</div>

			<!-- 关于 ECDSA -->
			<section id="about" class="mt-16 bg-white rounded-xl p-8 card-shadow">
				<h2 class="text-2xl font-bold mb-6 text-dark">关于 ECDSA</h2>
				<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
					<div>
						<h3 class="text-xl font-semibold mb-4 text-primary">什么是 ECDSA？</h3>
						<p class="text-gray-700 mb-4">
							ECDSA（Elliptic Curve Digital Signature
							Algorithm）是一种基于椭圆曲线密码学的数字签名算法。 它提供了与 RSA
							相当的安全性，但使用更短的密钥长度，因此在性能和效率上更具优势。
						</p>
						<p class="text-gray-700 mb-4">
							ECDSA 广泛应用于各种安全场景，包括加密货币（如比特币和以太坊）、SSL/TLS
							证书、 代码签名和身份验证系统等。
						</p>
						<h3 class="text-xl font-semibold mb-4 text-primary">工作原理</h3>
						<p class="text-gray-700 mb-4">
							ECDSA 使用一对密钥：私钥和公钥。私钥用于生成签名，而公钥用于验证签名。
							签名过程涉及对消息的哈希值进行数学运算，生成两个大整数（r 和
							s）作为签名。
						</p>
						<p class="text-gray-700">
							验证过程使用公钥、原始消息和签名值，通过椭圆曲线运算验证签名的有效性。
							如果签名有效，则证明消息确实是由持有相应私钥的人发送的，并且消息在传输过程中未被篡改。
						</p>
					</div>
					<div>
						<h3 class="text-xl font-semibold mb-4 text-primary">前端实现注意事项</h3>
						<ul class="space-y-3 text-gray-700">
							<li class="flex items-start">
								<i class="fa fa-lock text-primary mt-1 mr-2"></i>
								<span>私钥在前端生成和使用时，必须确保安全存储，避免泄露。</span>
							</li>
							<li class="flex items-start">
								<i class="fa fa-exchange text-primary mt-1 mr-2"></i>
								<span
									>签名和验证过程涉及复杂的数学运算，可能会影响性能，尤其是在移动设备上。</span
								>
							</li>
							<li class="flex items-start">
								<i class="fa fa-shield text-primary mt-1 mr-2"></i>
								<span
									>建议使用经过审计的密码学库，如 Web Crypto API 或
									elliptic.js，避免自行实现底层算法。</span
								>
							</li>
							<li class="flex items-start">
								<i class="fa fa-exclamation-triangle text-primary mt-1 mr-2"></i>
								<span
									>在实际应用中，考虑结合 HTTPS
									和其他安全措施，提供更全面的安全保障。</span
								>
							</li>
							<li class="flex items-start">
								<i class="fa fa-link text-primary mt-1 mr-2"></i>
								<span
									>ECDSA
									签名通常与消息哈希一起使用，确保消息完整性和防篡改。</span
								>
							</li>
						</ul>
						<h3 class="text-xl font-semibold mt-8 mb-4 text-primary">
							为什么选择 ECDSA？
						</h3>
						<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
							<div class="bg-gray-50 p-4 rounded-lg">
								<div class="text-primary text-2xl mb-2">
									<i class="fa fa-bolt"></i>
								</div>
								<h4 class="font-semibold mb-1">更高性能</h4>
								<p class="text-sm text-gray-600">
									与 RSA 相比，相同安全级别下密钥更短，计算效率更高。
								</p>
							</div>
							<div class="bg-gray-50 p-4 rounded-lg">
								<div class="text-primary text-2xl mb-2">
									<i class="fa fa-shield"></i>
								</div>
								<h4 class="font-semibold mb-1">同等安全</h4>
								<p class="text-sm text-gray-600">
									在相同密钥长度下，提供与 RSA 相当的安全性。
								</p>
							</div>
							<div class="bg-gray-50 p-4 rounded-lg">
								<div class="text-primary text-2xl mb-2">
									<i class="fa fa-mobile"></i>
								</div>
								<h4 class="font-semibold mb-1">移动友好</h4>
								<p class="text-sm text-gray-600">
									更小的密钥和更快的计算速度，适合资源受限的设备。
								</p>
							</div>
							<div class="bg-gray-50 p-4 rounded-lg">
								<div class="text-primary text-2xl mb-2">
									<i class="fa fa-globe"></i>
								</div>
								<h4 class="font-semibold mb-1">广泛应用</h4>
								<p class="text-sm text-gray-600">
									被众多安全标准和协议采纳，包括 TLS、PGP 和加密货币。
								</p>
							</div>
						</div>
					</div>
				</div>
			</section>
		</main>

		<!-- 页脚 -->
		<footer class="bg-dark text-white py-8 mt-16">
			<div class="container mx-auto px-4">
				<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
					<div>
						<div class="flex items-center space-x-2 mb-4">
							<i class="fa fa-shield text-primary text-2xl"></i>
							<h3 class="text-xl font-bold">ECDSA 前端示例</h3>
						</div>
						<p class="text-gray-400 mb-4">
							本示例展示了如何在前端使用 ECDSA 算法实现数字签名和验证功能，
							所有操作均在浏览器中完成，确保数据隐私和安全。
						</p>
						<div class="flex space-x-4">
							<a href="#" class="text-gray-400 hover:text-primary transition-colors">
								<i class="fa fa-github text-xl"></i>
							</a>
							<a href="#" class="text-gray-400 hover:text-primary transition-colors">
								<i class="fa fa-twitter text-xl"></i>
							</a>
							<a href="#" class="text-gray-400 hover:text-primary transition-colors">
								<i class="fa fa-linkedin text-xl"></i>
							</a>
						</div>
					</div>
					<div>
						<h4 class="text-lg font-semibold mb-4">快速链接</h4>
						<ul class="space-y-2">
							<li>
								<a
									href="#generate"
									class="text-gray-400 hover:text-primary transition-colors"
									>生成密钥对</a
								>
							</li>
							<li>
								<a
									href="#sign"
									class="text-gray-400 hover:text-primary transition-colors"
									>签名消息</a
								>
							</li>
							<li>
								<a
									href="#verify"
									class="text-gray-400 hover:text-primary transition-colors"
									>验证签名</a
								>
							</li>
							<li>
								<a
									href="#about"
									class="text-gray-400 hover:text-primary transition-colors"
									>关于 ECDSA</a
								>
							</li>
						</ul>
					</div>
					<div>
						<h4 class="text-lg font-semibold mb-4">安全资源</h4>
						<ul class="space-y-2">
							<li>
								<a
									href="https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm"
									target="_blank"
									class="text-gray-400 hover:text-primary transition-colors"
									>ECDSA 维基百科</a
								>
							</li>
							<li>
								<a
									href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API"
									target="_blank"
									class="text-gray-400 hover:text-primary transition-colors"
									>Web Crypto API</a
								>
							</li>
							<li>
								<a
									href="https://www.ietf.org/rfc/rfc6979.txt"
									target="_blank"
									class="text-gray-400 hover:text-primary transition-colors"
									>RFC 6979 (确定性 ECDSA)</a
								>
							</li>
							<li>
								<a
									href="https://cryptobook.nakov.com/digital-signatures/ecdsa-sign-verify-messages"
									target="_blank"
									class="text-gray-400 hover:text-primary transition-colors"
									>ECDSA 详解</a
								>
							</li>
						</ul>
					</div>
				</div>
				<div class="border-t border-gray-800 mt-8 pt-6 text-center text-gray-500">
					<p>© 2025 ECDSA 前端示例 | 使用 Tailwind CSS 和 Font Awesome 构建</p>
				</div>
			</div>
		</footer>

		<!-- JavaScript -->
		<script>
			// 移动端菜单切换
			document.getElementById("menu-toggle").addEventListener("click", function () {
				const mobileMenu = document.getElementById("mobile-menu");
				mobileMenu.classList.toggle("hidden");
			});

			// 导航栏滚动效果
			window.addEventListener("scroll", function () {
				const navbar = document.getElementById("navbar");
				if (window.scrollY > 20) {
					navbar.classList.add("py-2", "shadow-lg");
					navbar.classList.remove("py-3", "shadow-md");
				} else {
					navbar.classList.add("py-3", "shadow-md");
					navbar.classList.remove("py-2", "shadow-lg");
				}
			});

			// 平滑滚动
			document.querySelectorAll('a[href^="#"]').forEach(anchor => {
				anchor.addEventListener("click", function (e) {
					e.preventDefault();
					const targetId = this.getAttribute("href");
					const targetElement = document.querySelector(targetId);
					if (targetElement) {
						window.scrollTo({
							top: targetElement.offsetTop - 80,
							behavior: "smooth"
						});
						// 关闭移动菜单（如果打开）
						document.getElementById("mobile-menu").classList.add("hidden");
					}
				});
			});

			// ECDSA 功能实现
			document.addEventListener("DOMContentLoaded", function () {
				// 生成密钥对
				document
					.getElementById("generate-keys")
					.addEventListener("click", async function () {
						try {
							// 使用 Web Crypto API 生成 ECDSA 密钥对
							const keyPair = await window.crypto.subtle.generateKey(
								{
									name: "ECDSA",
									namedCurve: "P-256" // 可以选择 P-256, P-384 或 P-521
								},
								true, // 可导出
								["sign", "verify"]
							);

							// 导出公钥为 SPKI 格式
							const publicKey = await window.crypto.subtle.exportKey(
								"spki",
								keyPair.publicKey
							);

							// 导出私钥为 PKCS8 格式
							const privateKey = await window.crypto.subtle.exportKey(
								"pkcs8",
								keyPair.privateKey
							);

							// 转换为 PEM 格式
							const publicKeyPEM = arrayBufferToPem(publicKey, "PUBLIC KEY");
							const privateKeyPEM = arrayBufferToPem(privateKey, "PRIVATE KEY");

							// 显示密钥
							document.getElementById("public-key").value = publicKeyPEM;
							document.getElementById("private-key").value = privateKeyPEM;

							showNotification("密钥对生成成功！", "success");
						} catch (error) {
							console.error("生成密钥对时出错:", error);
							showNotification("生成密钥对失败: " + error.message, "error");
						}
					});

				// 签名消息
				document
					.getElementById("sign-message")
					.addEventListener("click", async function () {
						const message = document.getElementById("message-to-sign").value.trim();
						const privateKeyPEM = document
							.getElementById("private-key-sign")
							.value.trim();

						if (!message) {
							showNotification("请输入要签名的消息", "warning");
							return;
						}

						if (!privateKeyPEM) {
							showNotification("请提供私钥", "warning");
							return;
						}

						try {
							// 将 PEM 格式的私钥转换为 CryptoKey
							const privateKey = await importPrivateKey(privateKeyPEM);

							// 计算消息的哈希值
							const encoder = new TextEncoder();
							const data = encoder.encode(message);
							const digest = await window.crypto.subtle.digest("SHA-256", data);

							// 签名哈希值
							const signature = await window.crypto.subtle.sign(
								{
									name: "ECDSA",
									hash: { name: "SHA-256" }
								},
								privateKey,
								digest
							);

							// 将签名转换为 Base64 格式
							const signatureBase64 = arrayBufferToBase64(signature);

							// 显示签名结果
							document.getElementById("signature-result").value = signatureBase64;

							showNotification("消息签名成功！", "success");
						} catch (error) {
							console.error("签名消息时出错:", error);
							showNotification("签名消息失败: " + error.message, "error");
						}
					});

				// 验证签名
				document
					.getElementById("verify-signature")
					.addEventListener("click", async function () {
						const message = document.getElementById("message-to-verify").value.trim();
						const publicKeyPEM = document
							.getElementById("public-key-verify")
							.value.trim();
						const signatureBase64 = document
							.getElementById("signature-to-verify")
							.value.trim();

						if (!message) {
							showNotification("请输入原始消息", "warning");
							return;
						}

						if (!publicKeyPEM) {
							showNotification("请提供公钥", "warning");
							return;
						}

						if (!signatureBase64) {
							showNotification("请提供签名", "warning");
							return;
						}

						try {
							// 将 PEM 格式的公钥转换为 CryptoKey
							const publicKey = await importPublicKey(publicKeyPEM);

							// 将 Base64 格式的签名转换为 ArrayBuffer
							const signature = base64ToArrayBuffer(signatureBase64);

							// 计算消息的哈希值
							const encoder = new TextEncoder();
							const data = encoder.encode(message);
							const digest = await window.crypto.subtle.digest("SHA-256", data);

							// 验证签名
							const isValid = await window.crypto.subtle.verify(
								{
									name: "ECDSA",
									hash: { name: "SHA-256" }
								},
								publicKey,
								signature,
								digest
							);

							// 显示验证结果
							const resultElement = document.getElementById("verification-result");
							if (isValid) {
								resultElement.textContent =
									"签名验证成功！消息未被篡改，且确实由私钥持有者签名。";
								resultElement.className =
									"py-3 px-4 rounded-lg font-medium bg-green-100 text-green-800";
							} else {
								resultElement.textContent =
									"签名验证失败！消息可能被篡改，或者签名无效。";
								resultElement.className =
									"py-3 px-4 rounded-lg font-medium bg-red-100 text-red-800";
							}

							showNotification("签名验证完成！", "info");
						} catch (error) {
							console.error("验证签名时出错:", error);
							showNotification("验证签名失败: " + error.message, "error");
						}
					});

				// 使用生成的私钥进行签名
				document
					.getElementById("use-generated-private-key")
					.addEventListener("click", function () {
						const privateKey = document.getElementById("private-key").value;
						if (privateKey) {
							document.getElementById("private-key-sign").value = privateKey;
						} else {
							showNotification("请先生成密钥对", "warning");
						}
					});

				// 使用生成的公钥进行验证
				document
					.getElementById("use-generated-public-key")
					.addEventListener("click", function () {
						const publicKey = document.getElementById("public-key").value;
						if (publicKey) {
							document.getElementById("public-key-verify").value = publicKey;
						} else {
							showNotification("请先生成密钥对", "warning");
						}
					});

				// 复制功能
				document.getElementById("copy-public-key").addEventListener("click", function () {
					copyToClipboard("public-key", "公钥已复制到剪贴板");
				});

				document.getElementById("copy-private-key").addEventListener("click", function () {
					copyToClipboard("private-key", "私钥已复制到剪贴板");
				});

				document.getElementById("copy-signature").addEventListener("click", function () {
					copyToClipboard("signature-result", "签名已复制到剪贴板");
				});

				// 辅助函数
				function arrayBufferToBase64(buffer) {
					let binary = "";
					const bytes = new Uint8Array(buffer);
					for (let i = 0; i < bytes.byteLength; i++) {
						binary += String.fromCharCode(bytes[i]);
					}
					return window.btoa(binary);
				}

				function base64ToArrayBuffer(base64) {
					const binaryString = window.atob(base64);
					const bytes = new Uint8Array(binaryString.length);
					for (let i = 0; i < binaryString.length; i++) {
						bytes[i] = binaryString.charCodeAt(i);
					}
					return bytes.buffer;
				}

				function arrayBufferToPem(buffer, type) {
					const base64 = arrayBufferToBase64(buffer);
					let pem = `-----BEGIN ${type}-----\n`;
					const lines = Math.ceil(base64.length / 64);
					for (let i = 0; i < lines; i++) {
						pem += base64.substr(i * 64, 64) + "\n";
					}
					pem += `-----END ${type}-----`;
					return pem;
				}

				function pemToArrayBuffer(pem) {
					// 移除 PEM 头和尾
					const pemWithoutHeaders = pem
						.replace(/-----BEGIN [^-]+-----/g, "")
						.replace(/-----END [^-]+-----/g, "")
						.replace(/\s/g, "");
					return base64ToArrayBuffer(pemWithoutHeaders);
				}

				async function importPrivateKey(pem) {
					const buffer = pemToArrayBuffer(pem);
					return await window.crypto.subtle.importKey(
						"pkcs8",
						buffer,
						{
							name: "ECDSA",
							namedCurve: "P-256"
						},
						true,
						["sign"]
					);
				}

				async function importPublicKey(pem) {
					const buffer = pemToArrayBuffer(pem);
					return await window.crypto.subtle.importKey(
						"spki",
						buffer,
						{
							name: "ECDSA",
							namedCurve: "P-256"
						},
						true,
						["verify"]
					);
				}

				function copyToClipboard(elementId, message) {
					const element = document.getElementById(elementId);
					element.select();
					document.execCommand("copy");
					showNotification(message, "success");
				}

				function showNotification(message, type) {
					// 创建通知元素
					const notification = document.createElement("div");
					notification.className = `fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-lg z-50 transform transition-all duration-500 ease-in-out translate-y-20 opacity-0`;

					// 根据类型设置样式
					if (type === "success") {
						notification.classList.add("bg-green-500", "text-white");
						notification.innerHTML = `<i class="fa fa-check-circle mr-2"></i> ${message}`;
					} else if (type === "error") {
						notification.classList.add("bg-red-500", "text-white");
						notification.innerHTML = `<i class="fa fa-exclamation-circle mr-2"></i> ${message}`;
					} else if (type === "warning") {
						notification.classList.add("bg-yellow-500", "text-white");
						notification.innerHTML = `<i class="fa fa-exclamation-triangle mr-2"></i> ${message}`;
					} else if (type === "info") {
						notification.classList.add("bg-blue-500", "text-white");
						notification.innerHTML = `<i class="fa fa-info-circle mr-2"></i> ${message}`;
					}

					// 添加到文档
					document.body.appendChild(notification);

					// 显示通知
					setTimeout(() => {
						notification.classList.remove("translate-y-20", "opacity-0");
					}, 10);

					// 3秒后隐藏通知
					setTimeout(() => {
						notification.classList.add("translate-y-20", "opacity-0");
						setTimeout(() => {
							document.body.removeChild(notification);
						}, 500);
					}, 3000);
				}
			});
		</script>
	</body>
</html>
